﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Security;
using Monitor.Models.Json;
using Monitor.Models.JsonModel;
using Monitor.Repository.Development;
using Monitor.Repository.UserRepository.LinqModel;

namespace Monitor.Controllers.ApiControllers.AccountManager
{
    /// <summary>
    /// Контроллер по управлению деревом машинок
    /// </summary>
    public class UserTreeManagerController : MainApiController
    {
        /// <summary>
        /// Извлекает коллекцию доступных автомобилей
        /// </summary>
        /// <returns>Коллекция элементов дерева</returns>
        public Collection<TreeElementJson> Get()
        {
            //результирующая колекция
            Collection<TreeElementJson> result = new Collection<TreeElementJson>();
            try
            {
                //получаем словарь машин
                IDictionary<long, Car> userList = CurrentUser.Cars.ToDictionary(n => n.Fk_CarId);

                //проходимся по значениям словаря
                foreach (Car car in userList.Select(n => n.Value))
                {
                    TreeElementJson carJson = new TreeElementJson()
                                                  {
                                                      Id = car.CarId.ToString(),
                                                      ParentId = "-1",
                                                      Class = car.IconClass,
                                                      Name =
                                                          DataRepository.
                                                          CarRepository.GetCarById
                                                          (car.Fk_CarId).CarName()
                                                  };
                    result.Add(carJson);//добавляем в базу данных массив машин
                }

                Repository.DataRepository.LinqModel.Car[] cars = DataRepository
                    .CarRepository
                    .GetCars().ToArray()
                    .Where(allCar => !userList.ContainsKey(allCar.CarId))
                    .ToArray();//получаем массив недостающих машин (доступно админам в будущем)
                if (cars.Any())//если массив непустой
                {
                    TreeElementJson elseFolder = new TreeElementJson()
                                                     {
                                                         Id = "else",
                                                         ParentId = "-1",
                                                         Class = "elseGroup",
                                                         Name = "Другие"
                                                     };
                    result.Add(elseFolder);//добавляем узел "Другие"
                    foreach (Repository.DataRepository.LinqModel.Car car in cars)//проходимся по массиву значений
                    {
                        TreeElementJson carJson = new TreeElementJson()
                                                      {
                                                          Id = "else_" + car.CarId.ToString(),
                                                          ParentId = "else",
                                                          Class = "else",
                                                          Name = car.CarName()
                                                      };
                        result.Add(carJson);//добавляем в коллекцию
                    }
                }
            }
            catch (Exception exception)
            {
                ErrorLogger.Error(this.ControllerContext, exception);   //логируем ошибку
                return new Collection<TreeElementJson>();               //возвращаем пустой массив
            }
            return result;                                             //возвращаем результат
        }

        /// <summary>
        /// Запрос на добавление из списка всех доступных машин в дерево
        /// </summary>
        /// <param name="model">Модель нового элемента</param>
        /// <returns>Ок - если успешно, и сообщение об ошибке в противном случае</returns>
        public HttpResponseMessage Post(AddNewTreeItem model)
        {
            bool status = false;
            try
            {
                long groupId = 0;
                if (model.MasterId.StartsWith("tree_")&&long.TryParse(model.MasterId.Remove(0, 5), out groupId)) //вставка только в группу разрешена  
                {
                    if(string.IsNullOrEmpty(model.Label))                                   //если не указана метка (только для нового элемента)
                    {
                        if (!model.PointId.StartsWith("tree_"))                             //проверка на то, что не узел
                        {
                            long carId = 0;

                            if (model.PointId.StartsWith("else_") &&                        //новая ли точка
                                long.TryParse(model.PointId.Remove(0, 5), out carId))       //корректный id
                            {
                                if (DataRepository.CarRepository.GetCarById(carId) != null) //если машинка есть в БД (доступно только админам в будущем)
                                    status = UserRepository.AddNewCar(User.Identity.Name, carId, groupId) != null;
                            }
                            else if (long.TryParse(model.PointId, out carId))               //машинка у пользователя есть, но состоит в другой группе   
                            {
                                status = UserRepository.MoveCar(User.Identity.Name, carId, groupId);
                            }
                        }

                    }
                    else
                    {
                        if(!string.IsNullOrEmpty(model.Label))              //указан лейбло
                        {
                            status = UserRepository.AddNewGroup(User.Identity.Name, model.Label, groupId);  //добавляет новую группу
                        }
                    }
                    
                }
            }
            catch (Exception e)
            {
                ErrorLogger.Fatal(this,e);
                return Request.CreateResponse(HttpStatusCode.InternalServerError);
            }
            return (status)
                       ? Request.CreateResponse(HttpStatusCode.OK)
                       : Request.CreateResponse(HttpStatusCode.MethodNotAllowed);
        }

        /// <summary>
        /// Запрос на перемещение элементов внутри дерева
        /// </summary>
        /// <param name="id">индификатор узла, которую необходимо переместить</param>
        /// <param name="model">путь перемещения</param>
        /// <returns>Ок - если успешно, в противном случае сообщение об ошибке</returns>
        public HttpResponseMessage Put(string id, AddNewTreeItem model)
        {
            bool status = false;
            try
            {
                long nodeId = 0;        //индификатор точки
                long newGroupId = 0;    //индификатор точки назначения
                long oldGroupId = 0;    //индификатор предыдущей родительской
                if (!string.Equals(model.MasterId, model.PointId)//не осуществляется перемещение
                    //перемещение разрешено только в группу из группы
                    && model.MasterId.StartsWith("tree_") && model.PointId.StartsWith("tree_")
                    //и возможно получить индификатор группы
                    && long.TryParse(model.MasterId.Remove(0, 5), out newGroupId))
                {

                    if (id.StartsWith("tree_") && long.TryParse(id.Remove(0, 5), out nodeId)) //имеем дело с узлами
                    {
                        status = UserRepository.MoveGroup(User.Identity.Name, nodeId, newGroupId);
                    }
                    else if (long.TryParse(id, out nodeId)) //имеем дело с точками
                    {
                        if (long.TryParse(model.PointId.Remove(0, 5), out oldGroupId))
                            //и возможно получить индификатор старой группы
                        {
                            //возвращаем статус операции
                            status = UserRepository.MoveCar(User.Identity.Name, nodeId, newGroupId, oldGroupId);
                        }

                    }
                }
            }
            catch (Exception e)
            {
                ErrorLogger.Fatal(this, e);                                         //логирование ошибки
                return Request.CreateResponse(HttpStatusCode.InternalServerError);  //внутренняя ошибка
            }
            return (status)
                       ? Request.CreateResponse(HttpStatusCode.OK)                  //операция выполнена успешно
                       : Request.CreateResponse(HttpStatusCode.MethodNotAllowed);   //операция недоступна
        }

        /// <summary>
        /// Удаление узла дерева пользователя
        /// </summary>
        /// <param name="id">индификатор узла</param>
        public HttpResponseMessage Delete(string id,string parentId)
        {
            bool status = false;
            try
            {
                long nodeId = 0;        //индификатор точки
                long parentGroupId = 0;    //индификатор точки назначения
                //если возможно получить индификатор группы
                if (parentId.StartsWith("tree_")&& long.TryParse(parentId.Remove(0, 5), out parentGroupId))
                {
                    if (id.StartsWith("tree_")) //имеем дело с узлами
                    {
                        if (long.TryParse(id.Remove(0, 5), out nodeId))
                        {
                            //возвращаем статус операции
                           status = UserRepository.DeleteGroup(User.Identity.Name, nodeId); 
                        } 
                    }
                    else if (long.TryParse(id, out nodeId)) //имеем дело с точками
                    {
                        //возвращаем статус операции
                        status = UserRepository.DeleteCarFromGroup(User.Identity.Name, nodeId, parentGroupId);
                    }
                }
            }
            catch (Exception e)
            {
                ErrorLogger.Fatal(this, e);                                         //логирование ошибки
                return Request.CreateResponse(HttpStatusCode.InternalServerError);  //внутренняя ошибка
            }
            return (status)
                       ? Request.CreateResponse(HttpStatusCode.OK)                  //операция выполнена успешно
                       : Request.CreateResponse(HttpStatusCode.MethodNotAllowed);   //операция недоступна
        }
    }
}
